package chat.server;

import java.util.*;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ObjectOutputStream;
import java.net.Socket;

import chat.user.*;

public class SocketProcessor implements Runnable {

	private static Queue<Request> OutQueue = new LinkedList<Request>();
	private Object r;
	Object sync = new Object();

	public SocketProcessor() {

	}

	@Override
	public synchronized void run() {

		try {

			for (;; Thread.sleep(500)) { // used to improve performance

				// while (true) {

				synchronized (sync) {

					while (MultiThread.getCountInQueue() > 0) {

						r = MultiThread.getInMessage();

						if (r instanceof RequestGroupUpdate) {
							RequestGroupUpdate request = (RequestGroupUpdate) r;

							User user = GroupProcessor.getGroup(
									request.getUser().getRelatedGroup())
									.getUser(request.getUser().getUserName());

							Request response_message = MessageCreator
									.GroupUpdateRequestResponse(user,
											GroupProcessor.getGroupList());
							addMessageOutQueue(response_message);

						} else if (r instanceof RequestMessage) {

							RequestMessage request = (RequestMessage) r;

							Group g = GroupProcessor.getGroup(request.getUser()
									.getRelatedGroup());
							Vector<User> user_list = g.getUserList();
							for (User u : user_list) {
								if (!u.getUserName().equalsIgnoreCase(
										request.getUser().getUserName())) {
									addMessageOutQueue(MessageCreator
											.sendTextMessage(request
													.getMessage(), u, request
													.getUser().getUserName()));
								}
							}
						} else if (r instanceof RequestNewGroup) {
							RequestNewGroup request = (RequestNewGroup) r;
							GroupProcessor.addToGroupList(request.getGroup());

							sendGroupUpdateToAll();

						} else if (r instanceof RequestStatusUpdate) {

							RequestStatusUpdate request = (RequestStatusUpdate) r;

							Group g = GroupProcessor.getGroup(request.getUser()
									.getRelatedGroup());
							g.getUser(request.getUser().getUserName())
									.setStatus(request.getUser().getStatus());

							sendToAll(request);

						} else if (r instanceof RequestConnectGroup) {

							RequestConnectGroup request = (RequestConnectGroup) r;
							GroupProcessor.connectToGroup(request.getGroup(),
									request.getUser().getUserName());
							String name = request.getUser().getUserName();
							Vector<User> user_list2 = GroupProcessor.getGroup(
									request.getGroup()).getUserList();
							for (User u : user_list2) {
								if (name.equalsIgnoreCase(u.getUserName())) {
									addMessageOutQueue(MessageCreator
											.ConnectGroupRequestResponse(u,
													request.getGroup()));
								}
							}
						} else if (r instanceof RequestUserGroupUpdate) {

							Vector<Group> group_list = GroupProcessor
									.getGroupList();

							Map<String, Vector<User>> outcoming_group_user_list = new TreeMap<String, Vector<User>>();

							for (Group g : group_list) {

								outcoming_group_user_list.put(g.getName(),
										g.getUserList());
							}

							sendUserGroupUpdate(outcoming_group_user_list);

						} else if (r instanceof RequestChangeUserGroup) {

							RequestChangeUserGroup request = (RequestChangeUserGroup) r;

							sendChangeGroupUpdate(request);

						} else if (r instanceof RequestUserMessage) {

							String destination_user = ((RequestUserMessage) r)
									.getDestinationUser();

							Vector<Group> groups = GroupProcessor
									.getGroupList();
							User d_user = null;
							for (Group g : groups) {

								Vector<User> users = g.getUserList();

								for (User u : users) {

									if (destination_user.equalsIgnoreCase(u
											.getUserName())) {
										d_user = u;
										break;
									}
								}
							}

							RequestUserMessage response = new RequestUserMessage(
									((RequestUserMessage) r).getUser()
											.getUserName(), d_user);
							response.setMessage(((RequestUserMessage) r)
									.getMessage());
							addMessageOutQueue(response);

						} else if (r instanceof RequestRemoveGroup) {

							RequestRemoveGroup request = (RequestRemoveGroup) r;

							User user = null;

							Group group_to_remove = GroupProcessor
									.getGroup(request.getGroup());

							Vector<User> user_list = GroupProcessor.getGroup(
									request.getUser().getRelatedGroup())
									.getUsers();
							String name = request.getUser().getUserName();

							for (User u : user_list) {

								if (name.equalsIgnoreCase(u.getUserName())) {
									user = u;
								}
							}

							if (!group_to_remove.getName().equalsIgnoreCase(
									"General")) {

								if (group_to_remove.isEmpty()) {

									/*
									 * addMessageOutQueue(MessageCreator
									 * .RemoveGroupRequestResponse(s, true,
									 * request.getGroup()));
									 */
									GroupProcessor.getGroupList().remove(
											group_to_remove);

									sendGroupUpdateToAll();

								} else {

									addMessageOutQueue(MessageCreator
											.RemoveGroupRequestResponse(user,
													false, request.getGroup()));

								}
							} else {
								addMessageOutQueue(MessageCreator
										.RemoveGroupRequestResponse(user,
												false, request.getGroup()));
							}
						}
						MultiThread.RemoveFromInQueue(r);

					}
				}
			}
		} catch (Exception e) {

			e.printStackTrace();
		}

	}

	public static boolean addMessageOutQueue(Request r) {

		return OutQueue.add(r);
	}

	public static boolean removeMessageOutQueue(Request r) {

		return OutQueue.remove(r);
	}

	public static int getCountOutQueue() {

		return OutQueue.size();
	}

	public static Request getMessage() {

		return OutQueue.peek();

	}

	/*
	 * public static void process(Request r, Socket socket) {
	 * 
	 * GroupProcessor.registerNewUser(socket, r.getUser());
	 * 
	 * MessageCreator.AuthRequestResponse(socket);
	 * 
	 * SocketProcessor.addMessageOutQueue(MessageCreator
	 * .AuthRequestResponse(socket));
	 * 
	 * }
	 */

	public void sendGroupUpdateToAll() {

		Vector<Group> group_list = GroupProcessor.getGroupList();
		for (int i = 0; i < group_list.size(); i++) {
			Vector<User> user_list1 = group_list.get(i).getUserList();
			for (User u : user_list1) {
				addMessageOutQueue(MessageCreator.GroupUpdateRequestResponse(u,
						GroupProcessor.getGroupList()));
			}
		}
	}

	public void sendUserGroupUpdate(Map<String, Vector<User>> outcoming_groups) {

		Vector<Group> group_list = GroupProcessor.getGroupList();
		for (int i = 0; i < group_list.size(); i++) {
			Vector<User> user_list1 = group_list.get(i).getUserList();
			for (User u : user_list1) {

				RequestUserGroupUpdate response = new RequestUserGroupUpdate();

				response.setUserGroupList(outcoming_groups);

				response.setUser(u);

				addMessageOutQueue(response);

			}
		}
	}

	public void sendChangeGroupUpdate(RequestChangeUserGroup r) {

		// String old_group = r.getOldGroup();
		String new_group = r.getNewGroup();
		String old_group = r.getOldGroup();
		User user = r.getUser();

		Vector<Group> group_list = GroupProcessor.getGroupList();
		for (int i = 0; i < group_list.size(); i++) {
			Vector<User> user_list1 = group_list.get(i).getUserList();
			for (User u : user_list1) {

				if (!u.getUserName().equalsIgnoreCase((user.getUserName()))) {

					MessageCreator
							.requestChangedGroupUserResponse(u, new_group, old_group, user);
				}
			}
		}
	}

	public void sendToAll(RequestStatusUpdate request) {
		Vector<Group> group_list = GroupProcessor.getGroupList();
		for (int i = 0; i < group_list.size(); i++) {
			Vector<User> user_list1 = group_list.get(i).getUserList();
			for (User u : user_list1) {
				addMessageOutQueue(MessageCreator
						.requestUserStatusUpdateResponse(request.getUser()
								.getStatus(), request.getUser().getUserName(),
								u));

			}
		}
	}
}
